package com.peaksport.pkms.learntest.controller;

import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.core.MediaType;

import org.apache.servicecomb.pack.omega.context.annotations.SagaStart;
import org.apache.servicecomb.provider.rest.common.RestSchema;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.peaksport.framework.base.controller.BaseController;
import com.peaksport.framework.exception.PKDevException;
import com.peaksport.pkms.learntest.service.TestPackSagaService;

/**
 * 测试分布式事务框架Pack saga模式
 * 测试结论:
 *  1. sagaUI需改进
 *    a. UI上看不到事务的发生时间，不利分析事务异常的时间
 *    b. UI上需增加事务类型(start,end),否则从UI上看记录两两重复
 *    c. UI上需增加调用参数值，特别是补偿事务上，否则无从手工补偿修复事务
 *    d. 
 *
 * 
 *
 * @author jinbin_guo 2019年5月12日
 *
 */
@RestSchema(schemaId="pkms-test-pack-saga")
@RequestMapping(value="test/pack/saga",produces=MediaType.APPLICATION_JSON)
public class TestPackSagaController extends BaseController {

	@Autowired
	private TestPackSagaService service;

	private String cseService2  = "cse://pkms-test1/test/pack/saga/testAuditBillEntry?billId={billId}&isException={isException}&isExceptionInCancel={isExceptionInCancel}";
	/**
	 * 测试案例: 
	 *  1. 业务场景:
	 *    a. 共有2个 微服务,暂命名micservcie1&micservcie2
	 *    b. 在micservcie1里的controller里调用micservcie2
	 *    c. 服务调用采用同步调用的方式，非异步
	 *  2. 名称约定:
	 *    a. confirm表示在@Serivce中@Compensable的提交方法
	 *    b. cancel表示再@service中@Compensable的补偿方法
	 *    c. controller_invoke_service_after表示controller调用@service之后
	 *    d. controller_invoek_service_before表示controller调用@service之前
	 *    
	 * 
	 *  在Controller中调用第2个微服务事务
	 *  http://127.0.0.1:9100/test/pack/saga/testInvokeInController?billId=TLM%2FQ%2Bh%2FRr%2BqihLqUe6Tily2lGM%3D&isException=true&isExceptionInCancel=false&isException_service2=false&isExceptionInCancel_service2=false&isException_controller_after=false&isException_controller_middle=false
	 *  
	 *  
	 * 结论: 
	 * 	a. 当在micservice1.controller_invoke_service_after发生异常时,两事务都会回滚
	 *  b. 当在micservice1调用micservice2前发生异常, service1正常回滚,servier2未执行
	 *  c. 当在micservcie1.confirm发生异常,service1事务未提交,service2未执行
	 *  e. 当在micservcie2.confirm发生异常,service1事务回滚，servcie2事务未提交
	 *  f. 当在micservcie2.confirm、micservice1.cancel发生异常,service1事务回滚异常，servcie2事务未提交,，在sagaUI中补偿事务也无法查看到有效的补偿参数、方法
	 *  
	 *  
	 * @return
	 */
	@SagaStart
	@GetMapping("testInvokeInController")
	public String testInvokeInController(@RequestParam String billId,
					@RequestParam(required=false,defaultValue="false") boolean isException,
					@RequestParam(required=false,defaultValue="false") boolean isExceptionInCancel,
					@RequestParam(required=false,defaultValue="false") boolean isException_service2,
					@RequestParam(required=false,defaultValue="false") boolean isExceptionInCancel_service2,
					@RequestParam(required=false,defaultValue="false") boolean isException_controller_after,
					@RequestParam(required=false,defaultValue="false") boolean isException_controller_middle) {
		String str = doSerivce(billId, isException, isExceptionInCancel, isException_service2, 
				isExceptionInCancel_service2,isException_controller_middle);
		
//		service.auditBillHead(billId, isException, isExceptionInCancel);
//		Map<String,Object> queryMap = new HashMap<>();
//		queryMap.put("billId", urlEncode(billId));
//		queryMap.put("isException", isException_service2);
//		queryMap.put("isExceptionInCancel", isExceptionInCancel_service2);
//		if (isException_controller_middle) throw PKDevException.throwException("在调用service1后service2前发生异常.");
//		String msg = restTemplate.getForObject(cseService2,String.class,queryMap);
//		String str =  "测试testInvokeInController: " + "审核主表," + msg ;
		if (isException_controller_after) throw PKDevException.throwException("在controller1最后发生异常.");

		return str;
		
	}
	
	
	/**
	 * 测试案例: 
	 *  正常在Service中调用第2个微服务事务
	 *  测试结果与在controller中调用第2个微服务事务一样
	 * 
	 * @return
	 */
	@SagaStart
	@GetMapping("testInvokeInService")
	public String testInvokeInService(@RequestParam String billId,
			@RequestParam(required=false,defaultValue="false") boolean isException,
			@RequestParam(required=false,defaultValue="false") boolean isExceptionInCancel,
			@RequestParam(required=false,defaultValue="false") boolean isException_service2,
			@RequestParam(required=false,defaultValue="false") boolean isExceptionInCancel_service2,
			@RequestParam(required=false,defaultValue="false") boolean isException_controller_after,
			@RequestParam(required=false,defaultValue="false") boolean isException_controller_middle) {
		service.auditBillHead2(billId, isException, isExceptionInCancel,isException_service2,isExceptionInCancel_service2,isException_controller_middle);
		
		return "测试testInvokeInService";
	}
	
	
	/**
	 * 
	 * @param billId
	 * @param isException 
	 * @param isExceptionInCancel
	 * @param isException_service2
	 * @param isExceptionInCancel_service2 
	 * @return
	 */
	private String doSerivce(String billId, boolean isException, boolean isExceptionInCancel,
			boolean isException_service2,boolean isExceptionInCancel_service2,
			boolean isException_controller_middle) {
		
		
		service.auditBillHead(billId, isException, isExceptionInCancel);
		Map<String,Object> queryMap = new HashMap<>();
		queryMap.put("billId", urlEncode(billId));
		queryMap.put("isException", isException_service2);
		queryMap.put("isExceptionInCancel", isExceptionInCancel_service2);
		if (isException_controller_middle) throw PKDevException.throwException("在调用service1后service2前发生异常.");
		String msg = restTemplate.getForObject(cseService2,String.class,queryMap);
		
		return "测试testInvokeInController: " + "审核主表," + msg ;
	}
	
}
